package org.web.webdisplay.server.biz.impl;

import org.web.base.domain.ResultDO;
import org.web.webdisplay.sdk.dto.UserInfoDTO;
import org.web.webdisplay.sdk.dto.query.QueryUserInfoRequest;
import org.web.webdisplay.server.service.UserInfoService;

import java.util.*;

import org.springframework.stereotype.Service;
import org.springframework.beans.BeanUtils;

import jakarta.annotation.Resource;

import org.apache.log4j.Logger;
import org.web.webdisplay.sdk.biz.UserInfoBiz;
import org.web.webdisplay.server.domain.query.QueryUserInfo;
import org.web.webdisplay.server.domain.UserInfoDO;
import org.web.base.domain.exception.ResultMessageEnum;
import org.web.base.domain.helper.*;
import org.apache.commons.lang3.StringUtils;

import java.util.stream.Collectors;
import java.util.List;

@Service("userInfoBiz")
public class UserInfoBizImpl implements UserInfoBiz {

    private final Logger logger = Logger.getLogger(UserInfoBizImpl.class);

    @Resource
    private UserInfoService userInfoService;

    @Override
    public ResultDO<List<UserInfoDTO>> selectUserInfoList(QueryUserInfoRequest queryUserInfoRequest) {
        ResultDO<List<UserInfoDTO>> resultDO = new ResultDO<>();
        try {
            if (queryUserInfoRequest == null) {
                throw ServiceExceptionHelper.buildServiceException(ResultMessageEnum.PARAM_EMPTY);
            }
            queryUserInfoRequest.checkAndBuildQuery();
            ValidationHelper.validateWithThrow(QueryUserInfoRequest.class, queryUserInfoRequest);
            QueryUserInfo queryUserInfo = new QueryUserInfo();
            BeanUtils.copyProperties(queryUserInfoRequest, queryUserInfo);
            List<UserInfoDO> selectList = userInfoService.selectUserInfoList(queryUserInfo);
            List<UserInfoDTO> list = new ArrayList<>();
            resultDO.setDomain(list);
            for (UserInfoDO userInfoDO : selectList) {
                UserInfoDTO userInfoDTO = new UserInfoDTO();
                BeanUtils.copyProperties(userInfoDO, userInfoDTO);
                list.add(userInfoDTO);
            }
        } catch (Exception e) {
            logger.error(ServiceExceptionHelper.getExceptionInfo(e));
            return ResultHelper.buildResultDOByException(e);
        }
        return resultDO;
    }

    @Override
    public ResultDO<Integer> countUserInfoList(QueryUserInfoRequest queryUserInfoRequest) {
        ResultDO<Integer> resultDO = new ResultDO<>();
        try {
            if (queryUserInfoRequest == null) {
                throw ServiceExceptionHelper.buildServiceException(ResultMessageEnum.PARAM_EMPTY);
            }
            ValidationHelper.validateWithThrow(QueryUserInfoRequest.class, queryUserInfoRequest);
            QueryUserInfo queryUserInfo = new QueryUserInfo();
            BeanUtils.copyProperties(queryUserInfo, queryUserInfoRequest);
            Integer count = userInfoService.countUserInfoList(queryUserInfo);
            resultDO.setDomain(count);
        } catch (Exception e) {
            logger.error(ServiceExceptionHelper.getExceptionInfo(e));
            return ResultHelper.buildResultDOByException(e);
        }
        return resultDO;
    }

    @Override
    public ResultDO<List<UserInfoDTO>> batchSaveUserInfoList(List<UserInfoDTO> list) {
        ResultDO<List<UserInfoDTO>> resultDO = new ResultDO<>(true);
        try {
            resultDO.setDomain(list);
            if (list == null || list.isEmpty()) {
                throw ServiceExceptionHelper.buildServiceException(ResultMessageEnum.PARAM_EMPTY);
            }
            List<String> uniqueList = new ArrayList<>();
            List<UserInfoDTO> insertList = new LinkedList<>();
            List<UserInfoDTO> updateList = new LinkedList<>();
            List<Integer> primaryKeyList = new ArrayList<>();
            for (UserInfoDTO userInfoDTO : list) {
                if (userInfoDTO.getUserInfoId() == null) {
                    insertList.add(userInfoDTO);
                } else {
                    primaryKeyList.add(userInfoDTO.getUserInfoId());
                    updateList.add(userInfoDTO);
                }
                if (StringUtils.isNotBlank(userInfoDTO.getUserMail())) {
                    uniqueList.add(userInfoDTO.getUserMail());
                }
            }

            // 校验主键是否存在重复
            String duplicatesInfo = ListHelper.findDuplicatesByToString(primaryKeyList, ",");
            if (StringUtils.isNotBlank(duplicatesInfo)) {
                throw ServiceExceptionHelper.buildServiceException(ResultMessageEnum.PARAM_INVALID, "主键重复,重复主键：" + duplicatesInfo);
            }

            // 校验唯一性是否存在重复
            duplicatesInfo = ListHelper.findDuplicatesByToString(uniqueList, ",");
            if (StringUtils.isNotBlank(ListHelper.findDuplicatesByToString(uniqueList, ","))) {
                throw ServiceExceptionHelper.buildServiceException(ResultMessageEnum.PARAM_INVALID, "唯一性重复,重复信息：" + duplicatesInfo);
            }

            // 根据唯一性，从数据库判断是否存在重复数据，如果存在，则进行更新操作。
            List<UserInfoDTO> updateListFromInsertList = new ArrayList<>();
            for (UserInfoDTO userInfoDTO : insertList) {
                // 基于唯一性判断是否存在重复数据。
                QueryUserInfo queryUserInfo = new QueryUserInfo();
                queryUserInfo.setUserMail(userInfoDTO.getUserMail());
                UserInfoDO selectOneUserInfo = userInfoService.selectOneUserInfo(queryUserInfo);
                if (selectOneUserInfo != null) {
                    userInfoDTO.setUserInfoId(selectOneUserInfo.getUserInfoId());
                    updateListFromInsertList.add(userInfoDTO);
                }
            }

            // 校验更新数据是否存在重复
            if (!updateList.isEmpty()) {
                // 1. 提取待更新的所有主键ID
                Set<Integer> primaryKeySet = updateList.stream()
                        .map(UserInfoDTO::getUserInfoId)
                        .collect(Collectors.toSet());

                // 2. 查询数据库中实际存在的主键ID
                QueryUserInfo queryUserInfo = new QueryUserInfo();
                queryUserInfo.setAllRecords();
                queryUserInfo.setSpecifiedAttributeSet(new HashSet<>(List.of("user_info_id")));
                queryUserInfo.setUserInfoIdSet(primaryKeySet);
                List<UserInfoDO> selectList = userInfoService.selectUserInfoList(queryUserInfo);

                // 3. 提取数据库中存在的ID
                Set<Integer> existIds = selectList.stream()
                        .map(UserInfoDO::getUserInfoId)
                        .collect(Collectors.toSet());

                // 4. 找出待更新ID中不存在的ID
                Set<Integer> notExistIds = primaryKeySet.stream()
                        .filter(id -> !existIds.contains(id))
                        .collect(Collectors.toSet());

                // 5. 若存在不存在的ID，抛出异常并列出具体ID
                if (!notExistIds.isEmpty()) {
                    throw ServiceExceptionHelper.buildServiceException(
                            ResultMessageEnum.PARAM_INVALID,
                            "更新失败：以下主键ID不存在于数据库中：" + notExistIds.stream().map(String::valueOf).collect(Collectors.joining(", "))
                    );
                }
            }

            // 从insertList中移除updateListFromInsertList
            if (!updateListFromInsertList.isEmpty()) {
                for (UserInfoDTO userInfoDTO : updateListFromInsertList) {
                    updateList.add(userInfoDTO);
                    insertList.remove(userInfoDTO);
                }
            }

            if (!insertList.isEmpty()) {
                List<UserInfoDO> insertListForDomain = new ArrayList<>();
                for (UserInfoDTO userInfoDTO : insertList) {
                    UserInfoDO insertUserInfoDO = new UserInfoDO();
                    BeanUtils.copyProperties(userInfoDTO, insertUserInfoDO);
                    if (StringUtils.isBlank(userInfoDTO.getDepartmentName())) {
                        insertUserInfoDO.setDepartmentName(UserInfoDTO.DEPARTMENT_NAME_DEFAULT_VALUE);
                        userInfoDTO.setDepartmentName(UserInfoDTO.DEPARTMENT_NAME_DEFAULT_VALUE);
                    }
                    insertListForDomain.add(insertUserInfoDO);
                }
                List<UserInfoDO> insertRecords = userInfoService.batchInsertUserInfoList(insertListForDomain);
                Map<String, UserInfoDO> insertMap = new HashMap<>();
                for (UserInfoDO userInfoDO : insertRecords) {
                    insertMap.put(userInfoDO.getUserMail(), userInfoDO);
                }
                for (UserInfoDTO userInfoDTO : insertList) {
                    UserInfoDO userInfoDO = insertMap.get(userInfoDTO.getUserMail());
                    userInfoDTO.setUserInfoId(userInfoDO.getUserInfoId());
                    userInfoDTO.setCreateTime(userInfoDO.getCreateTime());
                    userInfoDTO.setUpdateTime(userInfoDO.getUpdateTime());
                }
            }

            if (!updateList.isEmpty()) {
                List<UserInfoDO> updateListOfDomain = new ArrayList<>();
                for (UserInfoDTO userInfoDTO : updateList) {
                    UserInfoDO userInfoDO = new UserInfoDO();
                    BeanUtils.copyProperties(userInfoDTO, userInfoDO);
                    updateListOfDomain.add(userInfoDO);
                }
                List<UserInfoDO> updateRecords = userInfoService.batchUpdateUserInfoList(updateListOfDomain);
                Map<Integer, UserInfoDO> updateMap = new HashMap<>();
                for (UserInfoDO userInfoDO : updateRecords) {
                    updateMap.put(userInfoDO.getUserInfoId(), userInfoDO);
                }
                for (UserInfoDTO userInfoDTO : updateList) {
                    UserInfoDO userInfoDO = updateMap.get(userInfoDTO.getUserInfoId());
                    userInfoDTO.setUpdateTime(userInfoDO.getUpdateTime());
                }
            }
        } catch (Exception e) {
            logger.error(ServiceExceptionHelper.getExceptionInfo(e));
            resultDO.setSuccess(false);
            resultDO.setMessage(e.getMessage());
        }
        return resultDO;
    }

    @Override
    public ResultDO<Integer> batchDeleteUserInfoList(List<Integer> userInfoIdList) {
        ResultDO<Integer> resultDO = new ResultDO<>();
        List<UserInfoDO> list = new ArrayList<>();
        for (Integer primaryKey : userInfoIdList) {
            UserInfoDO userInfoDO = new UserInfoDO();
            userInfoDO.setUserInfoId(primaryKey);
            //userInfoDO.setIsDelete("Y");
            list.add(userInfoDO);
        }
        int number = userInfoService.batchUpdateUserInfoList(list).size();
        resultDO.setDomain(number);
        return resultDO;
    }

}
